﻿using System.Text.Json.Serialization;
using Core.Caching;
using Core.Domain.Entities;
using Core.Domain.Enums;
using Core.Extensions;
using Core.Helpers;
using Core.Identity.Common.Interfaces.Common.Interfaces;
using Core.Identity.Roles.Caching;
using Core.Models;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Core.Identity.Roles.Features.Commands.AssignMenus;

/// <summary>
/// 分配权限
/// </summary>
public class AssignMenusToRoleCommand : ICacheInvalidatorRequest<Result<bool>>
{
    /// <summary>
    /// 角色Id
    /// </summary>
    public Guid RoleId { get; set; }

    /// <summary>
    /// 菜单Ids
    /// </summary>
    public List<Guid>? MenuIds { get; set; }

    [JsonIgnore]
    public IEnumerable<string>? Tags => RolesCacheKey.Tags;
}

public class AssignMenusToRoleCommandHandler(IIdentityDbContext dbContext) : IRequestHandler<AssignMenusToRoleCommand, Result<bool>>
{

    public async Task<Result<bool>> Handle(AssignMenusToRoleCommand request, CancellationToken cancellationToken)
    {
        var role = await dbContext.Roles
            .FirstOrDefaultAsync(x => x.Id == request.RoleId, cancellationToken);
        ExceptionHelper.ThrowIfNull(role, "角色不存在");

        var menus = await dbContext.Permissions
              .WhereIf(request.MenuIds != null && request.MenuIds.Count > 0, x => request.MenuIds!.Contains(x.Id))
              .ToListAsync(cancellationToken);
        if (menus.Any() && request.MenuIds?.Count > 0)
        {
            ExceptionHelper.ThrowIfFalse(menus.Count == request.MenuIds.Count, "菜单不存在");
        }

        var removeRolePermissions = await dbContext.RolePermissions.Where(x => x.RoleId == request.RoleId).ToListAsync();
        if (removeRolePermissions.Count != 0)
        {
            dbContext.RolePermissions.RemoveRange(removeRolePermissions);
        }

        if (request.MenuIds != null && request.MenuIds.Count > 0)
        {
            var rolePermissions = new List<RolePermission>();
            foreach (var menuId in request.MenuIds)
            {
                rolePermissions.Add(RolePermission.Create(role, menus.Find(x => x.Id == menuId), AccessState.Allow));
            }

            await dbContext.RolePermissions.AddRangeAsync(rolePermissions);
        }

        var result = await dbContext.SaveChangesAsync(cancellationToken) > 0;
        return await Result<bool>.SucceedAsync(result, result, ["操作失败"]);
    }
}

